import emitter from "@/utils/bus";

let lock = false;
let socket = null;
let isConnect = false;
let intervalTime = 20 * 1000;
let intervalObject = null;
let subscribeTopics = [];
let connectTimes = 0;

const connect = () => {
  if (connectTimes > 10) return;

  connectTimes++;
  if ("WebSocket" in window) {
    const ip = window.location.hostname;
    const port = window.location.port || '80';
    let context = import.meta.env.VITE_API_PATH;
    const protocol = window.location.protocol;
    let wsUrl;
    if (protocol.startsWith("https")) {
      wsUrl = "wss://" + ip + context + "/websocket";
    } else {
      wsUrl = "ws://" + ip + (port === '80' ? '' : (':' + port)) + context + "/websocket";
    }
    socket = new WebSocket(wsUrl);
    socket.onopen = onOpen;
    socket.onmessage = onMessage;
    socket.onclose = onClose;
    socket.onerror = onError;
  } else {
    console.log("浏览器不支持 WebSocket ！")
  }
};

const onOpen = () => {
  connectTimes = 0;
  isConnect = true;
  startMonitor();
  subscribeTopics.forEach(topic => send({type: topic}));
};

const onMessage = (res) => {
  try {
    const data = JSON.parse(res.data);
    if (data.topic === 'heartbeat') {
      // 心跳，不用处理
    } else if (data.topic === 'model.data.change') {
      emitter.emit(data.topic + "." + data.message);
    } else {
      emitter.emit(data.topic, data.message || '');
    }
  } catch (e) {
    console.log("websocket 消息处理失败！", e);
  }
};

const onClose = (res) => {
  console.log("websocket 连接关闭！", res);
  isConnect = false;
  reconnect();
};

const onError = (res) => {
  console.log("websocket 出错！", res);
};

const startMonitor = () => {
  if (intervalObject != null) {
    clearInterval(intervalObject);
    intervalObject = null;
  }

  intervalObject = setInterval(() => {
    if (socket.readyState !== 1) {
      try {
        socket.close();
      } catch (e) {
        console.log("websocket 异常时关闭出错！", e);
      }
      clearInterval(intervalObject);
      reconnect();
    } else {
      sendHeartbeat();
    }
  }, intervalTime);
};

const reconnect = () => {
  if (lock) return;

  lock = true;
  setTimeout(() => {
    connect();
    lock = false;
  }, 5 * 1000);
};

const addTopics = (topics) => {
  topics.forEach(topic => {
    if (!subscribeTopics.includes(topic)) {
      subscribeTopics.push(topic);
      if (isConnect) {
        send({type: topic});
      }
    }
  });
};

const sendHeartbeat = () => {
  send({type: 'heartbeat', message: 'ping'});
};

const send = (data) => {
  if (!data) return;
  socket.send(JSON.stringify(data));
};

const close = () => {
  isConnect = false;
  socket.close();
};

export default { connect, addTopics, send, close };